﻿using HP.UtilsLib;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.Storage;
using Windows.Storage.Streams;
using Xiaowei.Diagnostics;
using Xiaowei.Models;
using Debug = Xiaowei.Diagnostics.Debug;

namespace Xiaowei.Services
{
    //implement this player with MediaPlayer
    public class TTSPlayerWithMediaPlayer : ITTSPlayer
    {

        private MediaPlayer mediaPlayer;
        Stopwatch sw = new Stopwatch();

        //sometimes, playmedia will stop to work. For exiting under block 
        //timer is set.
        private readonly FailsafeTimer failsafeTimer = new FailsafeTimer();

        bool isPlaying = false;

        public event Action<bool> IsPlayingChanged;

        public bool IsPlaying
        {
            get
            {
                return isPlaying;
            }
            private set
            {
                if (isPlaying != value)
                {
                    isPlaying = value;
                    IsPlayingChanged?.Invoke(value);
                }
            }
        }

        public TTSPlayerWithMediaPlayer()
        {
            failsafeTimer.FailsafeTimeout += () =>
            {
                Debug.WriteLine($"TTSPlayerWithMediaPlayer Timeout");
                IsPlaying = false;
            };
        }

        public bool Play(string url)
        {
            lock (locker)
            {
                var wait = TaskAwaiterHelper.GetTaskAwaiter(
                    async () =>
                    {
                        return await PlayCore(url).ConfigureAwait(false);
                    }
                );
                var result = wait.GetResult();
                wait.Dispose();
                return result;
            }
        }
        private async Task<bool> PlayCore(string url)
        {
            Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:{url}");
            Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:waiter enter,URL{url}");
            failsafeTimer.Start(10000);
            Dispose();
            sw.Restart();
            mediaPlayer = new MediaPlayer();

            Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:Mdeia has been created  {url}");

            mediaPlayer.MediaEnded += (p, o) => {
                failsafeTimer.Stop();
                IsPlaying = false;
            };
            mediaPlayer.MediaFailed += (p, o) => {
                failsafeTimer.Stop();
                IsPlaying = false;
            };
            mediaPlayer.BufferingEnded += (p, o) =>
            {
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.BufferingEnded, {sw.ElapsedMilliseconds} ms.");
            };

            mediaPlayer.CurrentStateChanged += (p, o) =>
            {
                if (p.CurrentState == MediaPlayerState.Playing)
                {
                    Debug.WriteLine($"TTSPlayerWithMediaPlayer.MediaPlaying, {sw.ElapsedMilliseconds} ms.");
                    IsPlaying = true;

                }
            };
            var url2 = "https://cloudim.weixin.qq.com/cloudim/cloudxw-bin/xwttsplay?tts_id=TTS05uEetaE0TQPHa4_1-7-N94CzaUoaykUQZtuDNdP9-vnaPuXEWPKI24PEqMkcxyU5ysvwyTvno6dtBglmV1RFBSZgfF6VJuDLJxpLuEd8GAqHl0lMMvKBorJS3VwYokpaw_8o1u6dcLChu34sdsK07Wi7lKB5xvn96J69SycyuYIoqK3zU-4T-xL9kwwgjuvwKjwABFYpml1mAr2E7aHYEaJtWRLn8hAaNEJYNro0Or3EPL89tBcgLyLezAF2gAzQm6REWjOdx8zKAISR23Eyfob1J2clPERGM6NKivsbJeaIE7SXxhcZ8_gWwSAVsgDzh6xOv6S7CaN1xTFgGRO90fLhbfokjZHl-OaNc-JSEfMIAAAEB.mp3";
            //mediaPlayer.Source = MediaSource.CreateFromUri(new Uri(url));
            //var reference = RandomAccessStreamReference.CreateFromUri(new Uri(url));

            StorageFile file = null;
            if (url.StartsWith("ms-appx:"))
            {
                //local tts
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:load local tts  {url}");
                file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(url));
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:load local tts end  {url}");
            }
            else
            {
                //remote tts
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:load remote tts  {url}");
                var uri = new Uri(url);
                var reference = RandomAccessStreamReference.CreateFromUri(uri);
                file = await StorageFile.CreateStreamedFileFromUriAsync(".mp3", uri, reference);
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:load remote tts end  {url}");
            }
            Debug.WriteLine($"TTSPlayerWithMediaPlayer.mediaPlayer.StorageFile, {sw.ElapsedMilliseconds} ms  url:{url}.");
            if (file != null && file.IsAvailable)
            {
                mediaPlayer.Source = MediaSource.CreateFromStorageFile(file);
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.MediaSource.CreateFromStorageFile, {sw.ElapsedMilliseconds} ms. url:{url}");
                mediaPlayer.Play();
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.mediaPlayer.Play, {sw.ElapsedMilliseconds} ms  url:{url}.");
                IsPlaying = true;
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:{url} end ok");
                return true;
            }
            else
            {
                IsPlaying = false;
                failsafeTimer.Stop();
                Debug.WriteLine($"TTSPlayerWithMediaPlayer.Play:{url} end fail");
                return false;
            }
        }
        private readonly object locker = new object();
        public void Cancel()
        {
            lock (locker)
            {
                Debug.WriteLine("TTSPlayerWithMediaPlayer.Cancel");
                failsafeTimer.Stop();
                Debug.WriteLine("TTSPlayerWithMediaPlayer.Cancel enter waitor");
                if (IsPlaying)
                {
                    mediaPlayer?.Pause();
                    IsPlaying = false;
                }
                else
                {
                    Debug.WriteLine("TTSPlayerWithMediaPlayer.Play failed");
                }

                Debug.WriteLine("TTSPlayerWithMediaPlayer.Cancel end");
            }
        }

        private void Dispose()
        {
            //in some case, calling pause or dispose will be blocked.So running them
            //in a seperate thread.
            Debug.WriteLine("TTSPlayerWithMediaPlayer.Dispose");
            MediaPlayer player = mediaPlayer;
            mediaPlayer = null;
            Task.Run(() =>
            {
                Debug.WriteLine("TTSPlayerWithMediaPlayer.Dispose innner");
                if (player != null)
                {
                    Debug.WriteLine("TTSPlayer2.Stop");
                    player.Pause();
                    Debug.WriteLine("TTSPlayerWithMediaPlayer.Dispose paused");
                    player.Dispose();
                    Debug.WriteLine("TTSPlayer2.Stop end");
                }
                Debug.WriteLine("TTSPlayerWithMediaPlayer.Dispose inner end");
            });    
        }
    }
}
